package de.unikoblenz.west.csxpoi;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;

import android.text.SpannableString;
import android.text.style.UnderlineSpan;

/**
 * Helpers for formatting Strings and handling dates.
 * 
 * @author Daniel Schmei�
 * 
 */
public class Helpers {

	/**
	 * Creating an ISO8601-formatted string with the pattern
	 * "yyyy-MM-dd'T'HH:mm:ssZ"
	 * 
	 * @param year
	 *            int
	 * @param month
	 *            int
	 * @param day
	 *            int
	 * @param hour
	 *            int
	 * @param minutes
	 *            int
	 * @return String given dateTime in ISO8601 norm
	 */
	public static String formatToIsoDateTimeString(int year, int month,
			int day, int hour, int minutes) {
		String result = year + "-" + ((month < 10) ? "0" : "") + month + "-"
				+ ((day < 10) ? "0" : "") + day + "'T'"
				+ ((hour < 10) ? "0" : "") + hour + ":"
				+ ((minutes < 10) ? "0" : "") + minutes + ":00Z";

		return result;
	}

	/**
	 * formatIsoStringToNiceFormat formats the given string in ISO8601 norm in a
	 * human-readable format of "dd-MM-yyyy hh-mm"
	 * 
	 * @param isoString
	 *            String dateTime in ISO8601 norm
	 * @return String human-readable formatted string of the given string
	 */
	public static String formatIsoStringToNiceFormat(String isoString) {
		if (isoString.length() == 22) {
			String year = isoString.substring(0, 4);
			String month = isoString.substring(5, 7);
			String day = isoString.substring(8, 10);
			String hour = isoString.substring(13, 15);
			String minutes = isoString.substring(16, 18);
			return day + "-" + month + "-" + year + " " + hour + ":" + minutes;
		} else {
			return isoString;
		}
	}

	/**
	 * getCalendarOfIsoString returns the {@link Calendar} of the given ISO
	 * string. If the given string is not in ISO norm, the current date
	 * {@link Calendar} is returned.
	 * 
	 * @param isoString
	 *            String dateTime in ISO8601 norm
	 * @return {@link Calendar} corresponding to the given string
	 */
	public static Calendar getCalendarOfIsoString(String isoString) {
		Calendar cal = new GregorianCalendar(TimeZone.getDefault());
		if (isoString.length() == 22) {
			int year = Integer.valueOf(isoString.substring(0, 4));
			int month = Integer.valueOf(isoString.substring(5, 7)) - 1;
			int day = Integer.valueOf(isoString.substring(8, 10));
			int hour = Integer.valueOf(isoString.substring(13, 15));
			int minutes = Integer.valueOf(isoString.substring(16, 18));
			cal.set(year, month, day, hour, minutes);
		}
		return cal;
	}

	/**
	 * getCurrentDateTime returns the iso string representation of the current
	 * date.
	 * 
	 * @return String current date
	 */
	public static String getCurrentDateTime() {
		Calendar cal = new GregorianCalendar(TimeZone.getDefault());
		return formatToIsoDateTimeString(cal.get(Calendar.YEAR), cal
				.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), cal
				.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE));
	}

	/**
	 * getCurrentDateTime returns the iso string representation of the current
	 * date.
	 * 
	 * @return String current date XSD conform
	 */
	public static String getCurrentDateTimeXsdConform() {
		Calendar cal = new GregorianCalendar(TimeZone.getDefault());
		return formatToIsoDateTimeString(cal.get(Calendar.YEAR), cal
				.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), cal
				.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE));
	}

	/**
	 * getTomorrowDateTime returns the iso string representation of today plus
	 * 24 hours.
	 * 
	 * @return String today plus 24 hours
	 */
	public static String getTomorrowDateTime() {
		Calendar cal = new GregorianCalendar(TimeZone.getDefault());
		cal.roll(Calendar.DAY_OF_MONTH, true);
		return formatToIsoDateTimeString(cal.get(Calendar.YEAR), cal
				.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), cal
				.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE));
	}

	/**
	 * getTodayStart returns the iso string representation of the start of
	 * today's date.
	 * 
	 * @return String today date (00:00)
	 */
	public static String getTodayStart() {
		Calendar cal = new GregorianCalendar(TimeZone.getDefault());
		return formatToIsoDateTimeString(cal.get(Calendar.YEAR), cal
				.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), 0, 0);
	}

	/**
	 * getTodayEnd returns the iso string representation of the end of today's
	 * date.
	 * 
	 * @return String today date (23:59)
	 */
	public static String getTodayEnd() {
		Calendar cal = new GregorianCalendar(TimeZone.getDefault());
		return formatToIsoDateTimeString(cal.get(Calendar.YEAR), cal
				.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), 23,
				59);
	}

	/**
	 * getTomorrowStart returns the iso string representation of the start of
	 * the tomorrow date.
	 * 
	 * @return String tomorrow date (0:00)
	 */
	public static String getTomorrowStart() {
		Calendar cal = new GregorianCalendar(TimeZone.getDefault());
		cal.roll(Calendar.DAY_OF_MONTH, true);
		return formatToIsoDateTimeString(cal.get(Calendar.YEAR), cal
				.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), 0, 0);
	}

	/**
	 * getTomorrowEnd returns the iso string representation of the end of the
	 * tomorrow date.
	 * 
	 * @return String tomorrow date (23:59)
	 */
	public static String getTomorrowEnd() {
		Calendar cal = new GregorianCalendar(TimeZone.getDefault());
		cal.roll(Calendar.DAY_OF_MONTH, true);
		return formatToIsoDateTimeString(cal.get(Calendar.YEAR), cal
				.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), 23,
				59);
	}

	/**
	 * getOneWeekEnd returns the iso string representation of the end of the
	 * current date plus one week.
	 * 
	 * @return date plus one week
	 */
	public static String getOneWeekEnd() {
		Calendar cal = new GregorianCalendar(TimeZone.getDefault());
		cal.roll(Calendar.DAY_OF_MONTH, 7);
		return formatToIsoDateTimeString(cal.get(Calendar.YEAR), cal
				.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), 23,
				59);
	}

	/**
	 * daysBetween returns the count of days between the given {@link Calendar}
	 * s. Returns -1 if at least one of the given {@link Calendar}s is null or
	 * the start date is located after the end date.
	 * 
	 * @param startDate
	 *            {@link Calendar} start
	 * @param endDate
	 *            {@link Calendar} end
	 * @return long days between the given dates
	 */
	public static long daysBetween(Calendar startDate, Calendar endDate) {

		if (startDate == null || endDate == null)
			return -1;
		if (startDate.after(endDate))
			return -1;

		Calendar date = (Calendar) startDate.clone();
		long daysBetween = 0;
		while (date.before(endDate)) {
			date.add(Calendar.DAY_OF_MONTH, 1);
			daysBetween++;
		}
		return daysBetween;
	}

	/**
	 * getUnderlinedString returns a {@link SpannableString}, that contains the
	 * given string with underlined layout.
	 * 
	 * @param toUnderline
	 *            String
	 * @return {@link SpannableString}
	 */
	public static SpannableString getUnderlinedString(String toUnderline) {
		SpannableString str = SpannableString.valueOf(toUnderline);
		str.setSpan(new UnderlineSpan(), 0, toUnderline.length(), 0);
		return str;
	}
}
